<!DOCTYPE html>


<html lang="zh-CN">


<head>
  <meta charset="utf-8" />
    
  <meta name="description" content="迎着朝阳的博客" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    Spring核心之基于Annotation的IOC容器初始化 |  迎着朝阳
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="https://dxysun.com/static/yan.png" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">

  
<link rel="stylesheet" href="/css/custom.css">

  
  
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

  
  

  
<script>
var _hmt = _hmt || [];
(function() {
	var hm = document.createElement("script");
	hm.src = "https://hm.baidu.com/hm.js?aa994a8d65700b8835787dd39d079d7e";
	var s = document.getElementsByTagName("script")[0]; 
	s.parentNode.insertBefore(hm, s);
})();
</script>


</head>

</html>

<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-springForIOCAnnotation"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  Spring核心之基于Annotation的IOC容器初始化
</h1>
 

    </header>
     
    <div class="article-meta">
      <a href="/2021/08/30/springForIOCAnnotation/" class="article-date">
  <time datetime="2021-08-30T13:58:30.000Z" itemprop="datePublished">2021-08-30</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/spring/">spring</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">6.6k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">29 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <p>Spring核心之基于Annotation的IOC容器初始化</p>
<a id="more"></a>

<h1 id="基于Annotation的I0C初始化"><a href="#基于Annotation的I0C初始化" class="headerlink" title="基于Annotation的I0C初始化"></a>基于Annotation的I0C初始化</h1><p>Annotation的前世今生</p>
<p>从Spring2.0以后的版本中，Spring也引入了基于注解（Annotation）方式的配置，注解（Annotation）是JDK1.5中引入的一个新特性，用于简化Bean的配置，可以取代XML配置文件。</p>
<p>开发人员对注解（Annotation）的态度也是萝卜青菜各有所爱，注解可以大大简化配置，提高开发速度，但也给后期维护增加了难度。目前来说XML方式发展的相对成熟，方便于统一管理。随着Spring Boot的兴起，基于注解的开发甚至实现了零配置。但作为个人的习惯而言，还是倾向于XML配置文件和注解（Annotation）相互配合使用。</p>
<p>SpringIOC容器对于类级别的注解和类内部的注解分以下两种处理策略：</p>
<p>1）类级别的注解：如@Component、@Repository、@Controller、@Service 以及JavaEE6的@ManagedBean和@Named注解，都是添加在类上面的类级别注解，Spring容器根据注解的过滤规则扫描读取注解Bean定义类，并将其注册到SpringIOC容器中。</p>
<p>2）类内部的注解：如@Autowire、@Value、@Resource以及EJB和WebService相关的注解等，都是添加在类内部的字段或者方法上的类内部注解，SpringlOC容器通过Bean后置注解处理器解析Bean内部的注解。下面将根据这两种处理策略，分别分析Spring处理注解相关的源码。</p>
<h2 id="定位Bean扫描路径"><a href="#定位Bean扫描路径" class="headerlink" title="定位Bean扫描路径"></a>定位Bean扫描路径</h2><p>在Spring中管理注解Bean定义的容器有两个：AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContex。这两个类是专门处理Spring注解方式配置的容器，直接依赖于注解作为容器配置信息来源的IOC容器。</p>
<p>AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的Web版本，两者的用法以及对注解的处理方式几乎没有差别。现在以AnnotationConfigApplicationContext为例看看它的源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.springframework.context.annotation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.config.BeanDefinitionCustomizer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.support.BeanNameGenerator;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.support.DefaultListableBeanFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.GenericApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.env.ConfigurableEnvironment;</span><br><span class="line"><span class="keyword">import</span> org.springframework.lang.Nullable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.Assert;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.function.Supplier;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AnnotationConfigApplicationContext</span> <span class="keyword">extends</span> <span class="title">GenericApplicationContext</span> <span class="keyword">implements</span> <span class="title">AnnotationConfigRegistry</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//保存一个读取注解的Bean定义读取器，并将其设置到容器中</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">final</span> AnnotatedBeanDefinitionReader reader;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//保存一个扫描指定类路径中注解Bean定义的扫描器，并将其设置到容器中</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">final</span> ClassPathBeanDefinitionScanner scanner;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//默认构造函数，初始化一个空容器，容器不包含任何 Bean 信息，需要在稍后通过调用其register()</span></span><br><span class="line">	<span class="comment">//方法注册配置类，并调用refresh()方法刷新容器，触发容器对注解Bean的载入、解析和注册过程</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">AnnotationConfigApplicationContext</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.reader = <span class="keyword">new</span> AnnotatedBeanDefinitionReader(<span class="keyword">this</span>);</span><br><span class="line">		<span class="keyword">this</span>.scanner = <span class="keyword">new</span> ClassPathBeanDefinitionScanner(<span class="keyword">this</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">AnnotationConfigApplicationContext</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>(beanFactory);</span><br><span class="line">		<span class="keyword">this</span>.reader = <span class="keyword">new</span> AnnotatedBeanDefinitionReader(<span class="keyword">this</span>);</span><br><span class="line">		<span class="keyword">this</span>.scanner = <span class="keyword">new</span> ClassPathBeanDefinitionScanner(<span class="keyword">this</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//最常用的构造函数，通过将涉及到的配置类传递给该构造函数，以实现将相应配置类中的Bean自动注册到容器中</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">AnnotationConfigApplicationContext</span><span class="params">(Class&lt;?&gt;... annotatedClasses)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>();</span><br><span class="line">		register(annotatedClasses);</span><br><span class="line">		refresh();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//该构造函数会自动扫描以给定的包及其子包下的所有类，并自动识别所有的Spring Bean，将其注册到容器中</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">AnnotationConfigApplicationContext</span><span class="params">(String... basePackages)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>();</span><br><span class="line">		scan(basePackages);</span><br><span class="line">		refresh();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setEnvironment</span><span class="params">(ConfigurableEnvironment environment)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>.setEnvironment(environment);</span><br><span class="line">		<span class="keyword">this</span>.reader.setEnvironment(environment);</span><br><span class="line">		<span class="keyword">this</span>.scanner.setEnvironment(environment);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//为容器的注解Bean读取器和注解Bean扫描器设置Bean名称产生器</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setBeanNameGenerator</span><span class="params">(BeanNameGenerator beanNameGenerator)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.reader.setBeanNameGenerator(beanNameGenerator);</span><br><span class="line">		<span class="keyword">this</span>.scanner.setBeanNameGenerator(beanNameGenerator);</span><br><span class="line">		getBeanFactory().registerSingleton(</span><br><span class="line">				AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//为容器的注解Bean读取器和注解Bean扫描器设置作用范围元信息解析器</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setScopeMetadataResolver</span><span class="params">(ScopeMetadataResolver scopeMetadataResolver)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.reader.setScopeMetadataResolver(scopeMetadataResolver);</span><br><span class="line">		<span class="keyword">this</span>.scanner.setScopeMetadataResolver(scopeMetadataResolver);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//为容器注册一个要被处理的注解Bean，新注册的Bean，必须手动调用容器的</span></span><br><span class="line">	<span class="comment">//refresh()方法刷新容器，触发容器对新注册的Bean的处理</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(Class&lt;?&gt;... annotatedClasses)</span> </span>&#123;</span><br><span class="line">		Assert.notEmpty(annotatedClasses, <span class="string">"At least one annotated class must be specified"</span>);</span><br><span class="line">		<span class="keyword">this</span>.reader.register(annotatedClasses);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="comment">//扫描指定包路径及其子包下的注解类，为了使新添加的类被处理，必须手动调用</span></span><br><span class="line">	<span class="comment">//refresh()方法刷新容器</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">scan</span><span class="params">(String... basePackages)</span> </span>&#123;</span><br><span class="line">		Assert.notEmpty(basePackages, <span class="string">"At least one base package must be specified"</span>);</span><br><span class="line">		<span class="keyword">this</span>.scanner.scan(basePackages);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="keyword">public</span> &lt;T&gt; <span class="function"><span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(Class&lt;T&gt; annotatedClass, Object... constructorArguments)</span> </span>&#123;</span><br><span class="line">		registerBean(<span class="keyword">null</span>, annotatedClass, constructorArguments);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">public</span> &lt;T&gt; <span class="function"><span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(@Nullable String beanName, Class&lt;T&gt; annotatedClass, Object... constructorArguments)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.reader.doRegisterBean(annotatedClass, <span class="keyword">null</span>, beanName, <span class="keyword">null</span>,</span><br><span class="line">				bd -&gt; &#123;</span><br><span class="line">					<span class="keyword">for</span> (Object arg : constructorArguments) &#123;</span><br><span class="line">						bd.getConstructorArgumentValues().addGenericArgumentValue(arg);</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> &lt;T&gt; <span class="function"><span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(@Nullable String beanName, Class&lt;T&gt; beanClass, @Nullable Supplier&lt;T&gt; supplier,</span></span></span><br><span class="line"><span class="function"><span class="params">			BeanDefinitionCustomizer... customizers)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">this</span>.reader.doRegisterBean(beanClass, supplier, beanName, <span class="keyword">null</span>, customizers);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>通过上面的源码分析，我们可以看啊到Spring对注解的处理分为两种方式：</p>
<p>1）直接将注解Bean注册到容器中</p>
<p>可以在初始化容器时注册；也可以在容器创建之后手动调用注册方法向容器注册，然后通过手动刷新容器，使得容器能解Bean进行处理。</p>
<p>2）通过扫描指定的包及其子包下的所有类</p>
<p>在初始化注解容器时指定要自动扫描的路径，如果容器创建以后向指定路径动态添加了注解Bean，则需要手动调用容器扫描的方法，然后手动刷新容器，使得容器对所注册的Bean进行处理。</p>
<p>接下来，将会对两种处理方式详细分析其实现过程。</p>
<h3 id="读取Annotation元数据"><a href="#读取Annotation元数据" class="headerlink" title="读取Annotation元数据"></a>读取Annotation元数据</h3><p>当创建注解处理容器时，如果传入的初始参数是具体的注解Bean定义类时，注解容器读取并注册。</p>
<h4 id="1）AnnotationConfigApplicationContext通过调用注解Bean定义读取器"><a href="#1）AnnotationConfigApplicationContext通过调用注解Bean定义读取器" class="headerlink" title="1）AnnotationConfigApplicationContext通过调用注解Bean定义读取器"></a>1）AnnotationConfigApplicationContext通过调用注解Bean定义读取器</h4><p><code>AnnotatedBeanDefinitionReader的register()</code>方法向容器注册指定的注解Bean，注解Bean定义读取器向容器注册注解Bean的源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//注册多个注解Bean定义类</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(Class&lt;?&gt;... annotatedClasses)</span> </span>&#123;</span><br><span class="line">	<span class="keyword">for</span> (Class&lt;?&gt; annotatedClass : annotatedClasses) &#123;</span><br><span class="line">		registerBean(annotatedClass);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//注册一个注解Bean定义类</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(Class&lt;?&gt; annotatedClass)</span> </span>&#123;</span><br><span class="line">	doRegisterBean(annotatedClass, <span class="keyword">null</span>, <span class="keyword">null</span>, <span class="keyword">null</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function"><span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(Class&lt;T&gt; annotatedClass, @Nullable Supplier&lt;T&gt; instanceSupplier)</span> </span>&#123;</span><br><span class="line">	doRegisterBean(annotatedClass, instanceSupplier, <span class="keyword">null</span>, <span class="keyword">null</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function"><span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(Class&lt;T&gt; annotatedClass, String name, @Nullable Supplier&lt;T&gt; instanceSupplier)</span> </span>&#123;</span><br><span class="line">	doRegisterBean(annotatedClass, instanceSupplier, name, <span class="keyword">null</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//Bean定义读取器注册注解Bean定义的入口方法</span></span><br><span class="line"><span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(Class&lt;?&gt; annotatedClass, Class&lt;? extends Annotation&gt;... qualifiers)</span> </span>&#123;</span><br><span class="line">	doRegisterBean(annotatedClass, <span class="keyword">null</span>, <span class="keyword">null</span>, qualifiers);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//Bean定义读取器向容器注册注解Bean定义类</span></span><br><span class="line"><span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerBean</span><span class="params">(Class&lt;?&gt; annotatedClass, String name, Class&lt;? extends Annotation&gt;... qualifiers)</span> </span>&#123;</span><br><span class="line">	doRegisterBean(annotatedClass, <span class="keyword">null</span>, name, qualifiers);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//Bean定义读取器向容器注册注解Bean定义类</span></span><br><span class="line">&lt;T&gt; <span class="function"><span class="keyword">void</span> <span class="title">doRegisterBean</span><span class="params">(Class&lt;T&gt; annotatedClass, @Nullable Supplier&lt;T&gt; instanceSupplier, @Nullable String name,</span></span></span><br><span class="line"><span class="function"><span class="params">		@Nullable Class&lt;? extends Annotation&gt;[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//根据指定的注解Bean定义类，创建Spring容器中对注解Bean的封装的数据结构</span></span><br><span class="line">	AnnotatedGenericBeanDefinition abd = <span class="keyword">new</span> AnnotatedGenericBeanDefinition(annotatedClass);</span><br><span class="line">	<span class="keyword">if</span> (<span class="keyword">this</span>.conditionEvaluator.shouldSkip(abd.getMetadata())) &#123;</span><br><span class="line">		<span class="keyword">return</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	abd.setInstanceSupplier(instanceSupplier);</span><br><span class="line">	<span class="comment">//========第一步===========================</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">//解析注解Bean定义的作用域，若@Scope("prototype")，则Bean为原型类型；</span></span><br><span class="line">	<span class="comment">//若@Scope("singleton")，则Bean为单态类型</span></span><br><span class="line">	ScopeMetadata scopeMetadata = <span class="keyword">this</span>.scopeMetadataResolver.resolveScopeMetadata(abd);</span><br><span class="line">	<span class="comment">//为注解Bean定义设置作用域</span></span><br><span class="line">	abd.setScope(scopeMetadata.getScopeName());</span><br><span class="line">	<span class="comment">//为注解Bean定义生成Bean名称</span></span><br><span class="line">	String beanName = (name != <span class="keyword">null</span> ? name : <span class="keyword">this</span>.beanNameGenerator.generateBeanName(abd, <span class="keyword">this</span>.registry));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="comment">//========第二步===========================</span></span><br><span class="line">	<span class="comment">//处理注解Bean定义中的通用注解</span></span><br><span class="line">	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);</span><br><span class="line">	<span class="comment">//如果在向容器注册注解Bean定义时，使用了额外的限定符注解，则解析限定符注解。</span></span><br><span class="line">	<span class="comment">//主要是配置的关于autowiring自动依赖注入装配的限定条件，即@Qualifier注解</span></span><br><span class="line">	<span class="comment">//Spring自动依赖注入装配默认是按类型装配，如果使用@Qualifier则按名称</span></span><br><span class="line">	<span class="keyword">if</span> (qualifiers != <span class="keyword">null</span>) &#123;</span><br><span class="line">		<span class="keyword">for</span> (Class&lt;? extends Annotation&gt; qualifier : qualifiers) &#123;</span><br><span class="line">			<span class="comment">//如果配置了@Primary注解，设置该Bean为autowiring自动依赖注入装//配时的首选</span></span><br><span class="line">			<span class="keyword">if</span> (Primary<span class="class">.<span class="keyword">class</span> </span>== qualifier) &#123;</span><br><span class="line">				abd.setPrimary(<span class="keyword">true</span>);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="comment">//如果配置了@Lazy注解，则设置该Bean为非延迟初始化，如果没有配置，</span></span><br><span class="line">			<span class="comment">//则该Bean为预实例化</span></span><br><span class="line">			<span class="keyword">else</span> <span class="keyword">if</span> (Lazy<span class="class">.<span class="keyword">class</span> </span>== qualifier) &#123;</span><br><span class="line">				abd.setLazyInit(<span class="keyword">true</span>);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="comment">//如果使用了除@Primary和@Lazy以外的其他注解，则为该Bean添加一</span></span><br><span class="line">			<span class="comment">//个autowiring自动依赖注入装配限定符，该Bean在进autowiring</span></span><br><span class="line">			<span class="comment">//自动依赖注入装配时，根据名称装配限定符指定的Bean</span></span><br><span class="line">			<span class="keyword">else</span> &#123;</span><br><span class="line">				abd.addQualifier(<span class="keyword">new</span> AutowireCandidateQualifier(qualifier));</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">for</span> (BeanDefinitionCustomizer customizer : definitionCustomizers) &#123;</span><br><span class="line">		customizer.customize(abd);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//创建一个指定Bean名称的Bean定义对象，封装注解Bean定义类数据</span></span><br><span class="line">	BeanDefinitionHolder definitionHolder = <span class="keyword">new</span> BeanDefinitionHolder(abd, beanName);</span><br><span class="line">	<span class="comment">//========第三步===========================</span></span><br><span class="line">	<span class="comment">//根据注解Bean定义类中配置的作用域，创建相应的代理对象</span></span><br><span class="line">	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, <span class="keyword">this</span>.registry);</span><br><span class="line">	<span class="comment">//========第四步===========================</span></span><br><span class="line">	<span class="comment">//向IOC容器注册注解Bean类定义对象</span></span><br><span class="line">	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, <span class="keyword">this</span>.registry);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>从上面的源码我们可以看出，注册注解Bean定义类的基本步骤：</p>
<p>a、需要使用注解元数据解析器解析注解Bean中关于作用域的配置。</p>
<p>b、使用AnnotationConfigUtils的processCommonDefinitionAnnotations()方法处理注解Bean定义类中通用的注解。</p>
<p>c、使用AnnotationConfigUtils的applyScopedProxyMode()方法创建对于作用域的代理对象。 </p>
<p>d、通过BeanDefinitionReaderUtils向容器注册Bean。</p>
<p>下面继续分析这4步的具体实现过程</p>
<h4 id="2）AnnotationScopeMetadataResolver解析作用域元数据"><a href="#2）AnnotationScopeMetadataResolver解析作用域元数据" class="headerlink" title="2）AnnotationScopeMetadataResolver解析作用域元数据"></a>2）AnnotationScopeMetadataResolver解析作用域元数据</h4><p>AnnotationScopeMetadataResolver通过<code>resolveScopeMetadata()</code>方法解析注解Bean定义类的作用域元信息，即判断注册的Bean是原生类型（prototype）还是单态（singleton）类型，其源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//解析注解Bean定义类中的作用域元信息</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ScopeMetadata <span class="title">resolveScopeMetadata</span><span class="params">(BeanDefinition definition)</span> </span>&#123;</span><br><span class="line">	ScopeMetadata metadata = <span class="keyword">new</span> ScopeMetadata();</span><br><span class="line">	<span class="keyword">if</span> (definition <span class="keyword">instanceof</span> AnnotatedBeanDefinition) &#123;</span><br><span class="line">		AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;</span><br><span class="line">		<span class="comment">//从注解Bean定义类的属性中查找属性为”Scope”的值，即@Scope注解的值</span></span><br><span class="line">		<span class="comment">//AnnotationConfigUtils.attributesFor()方法将Bean中所有的注解和注解的值存放在一个map集合中</span></span><br><span class="line">		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(</span><br><span class="line">				annDef.getMetadata(), <span class="keyword">this</span>.scopeAnnotationType);</span><br><span class="line">		<span class="comment">//将获取到的@Scope注解的值设置到要返回的对象中</span></span><br><span class="line">		<span class="keyword">if</span> (attributes != <span class="keyword">null</span>) &#123;</span><br><span class="line">			metadata.setScopeName(attributes.getString(<span class="string">"value"</span>));</span><br><span class="line">			<span class="comment">//获取@Scope注解中的proxyMode属性值，在创建代理对象时会用到</span></span><br><span class="line">			ScopedProxyMode proxyMode = attributes.getEnum(<span class="string">"proxyMode"</span>);</span><br><span class="line">			<span class="comment">//如果@Scope的proxyMode属性为DEFAULT或者NO</span></span><br><span class="line">			<span class="keyword">if</span> (proxyMode == ScopedProxyMode.DEFAULT) &#123;</span><br><span class="line">				<span class="comment">//设置proxyMode为NO</span></span><br><span class="line">				proxyMode = <span class="keyword">this</span>.defaultProxyMode;</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="comment">//为返回的元数据设置proxyMode</span></span><br><span class="line">			metadata.setScopedProxyMode(proxyMode);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//返回解析的作用域元信息对象</span></span><br><span class="line">	<span class="keyword">return</span> metadata;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上述代码中的<code>annDef.getMetadata().getAnnotationAttributes()</code>方法就是获取对象中指定类型的注解的值。</p>
<h4 id="3）AnnotationConfigUtils处理注解Bean定义类中的通用注解"><a href="#3）AnnotationConfigUtils处理注解Bean定义类中的通用注解" class="headerlink" title="3）AnnotationConfigUtils处理注解Bean定义类中的通用注解"></a>3）AnnotationConfigUtils处理注解Bean定义类中的通用注解</h4><p>AnnotationConfigUtils类的<code>processCommonDefinitionAnnotations()</code>在向容器注册Bean之前，首<br>先对注解Bean定义类中的通用Spring注解进行处理，源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">processCommonDefinitionAnnotations</span><span class="params">(AnnotatedBeanDefinition abd)</span> </span>&#123;</span><br><span class="line">	processCommonDefinitionAnnotations(abd, abd.getMetadata());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//处理Bean定义中通用注解</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">processCommonDefinitionAnnotations</span><span class="params">(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata)</span> </span>&#123;</span><br><span class="line">	AnnotationAttributes lazy = attributesFor(metadata, Lazy<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">	<span class="comment">//如果Bean定义中有@Lazy注解，则将该Bean预实例化属性设置为@lazy注解的值</span></span><br><span class="line">	<span class="keyword">if</span> (lazy != <span class="keyword">null</span>) &#123;</span><br><span class="line">		abd.setLazyInit(lazy.getBoolean(<span class="string">"value"</span>));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span> (abd.getMetadata() != metadata) &#123;</span><br><span class="line">		lazy = attributesFor(abd.getMetadata(), Lazy<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">		<span class="keyword">if</span> (lazy != <span class="keyword">null</span>) &#123;</span><br><span class="line">			abd.setLazyInit(lazy.getBoolean(<span class="string">"value"</span>));</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//如果Bean定义中有@Primary注解，则为该Bean设置为autowiring自动依赖注入装配的首选对象</span></span><br><span class="line">	<span class="keyword">if</span> (metadata.isAnnotated(Primary<span class="class">.<span class="keyword">class</span>.<span class="title">getName</span>())) </span>&#123;</span><br><span class="line">		abd.setPrimary(<span class="keyword">true</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//如果Bean定义中有@DependsOn注解，则为该Bean设置所依赖的Bean名称，</span></span><br><span class="line">	<span class="comment">//容器将确保在实例化该Bean之前首先实例化所依赖的Bean</span></span><br><span class="line">	AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">	<span class="keyword">if</span> (dependsOn != <span class="keyword">null</span>) &#123;</span><br><span class="line">		abd.setDependsOn(dependsOn.getStringArray(<span class="string">"value"</span>));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (abd <span class="keyword">instanceof</span> AbstractBeanDefinition) &#123;</span><br><span class="line">		AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;</span><br><span class="line">		AnnotationAttributes role = attributesFor(metadata, Role<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">		<span class="keyword">if</span> (role != <span class="keyword">null</span>) &#123;</span><br><span class="line">			absBd.setRole(role.getNumber(<span class="string">"value"</span>).intValue());</span><br><span class="line">		&#125;</span><br><span class="line">		AnnotationAttributes description = attributesFor(metadata, Description<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">		<span class="keyword">if</span> (description != <span class="keyword">null</span>) &#123;</span><br><span class="line">			absBd.setDescription(description.getString(<span class="string">"value"</span>));</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="4）AnnotationConfigUtils根据注解Bean定义类中配置的作用域为其应用相应的代理策略"><a href="#4）AnnotationConfigUtils根据注解Bean定义类中配置的作用域为其应用相应的代理策略" class="headerlink" title="4）AnnotationConfigUtils根据注解Bean定义类中配置的作用域为其应用相应的代理策略"></a>4）AnnotationConfigUtils根据注解Bean定义类中配置的作用域为其应用相应的代理策略</h4><p>AnnotationConfigUtils类的<code>applyScopedProxyMode()</code>方法根据注解Bean定义类中配置的作用域 @Scope注解的值，为Bean定义应用相应的代理模式，主要是在Spring面向切面编程（AOP）中使用。 源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//根据作用域为Bean应用引用的代码模式</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> BeanDefinitionHolder <span class="title">applyScopedProxyMode</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">		ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//获取注解Bean定义类中@Scope注解的proxyMode属性值</span></span><br><span class="line">	ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();</span><br><span class="line">	<span class="comment">//如果配置的@Scope注解的proxyMode属性值为NO，则不应用代理模式</span></span><br><span class="line">	<span class="keyword">if</span> (scopedProxyMode.equals(ScopedProxyMode.NO)) &#123;</span><br><span class="line">		<span class="keyword">return</span> definition;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//获取配置的@Scope注解的proxyMode属性值，如果为TARGET_CLASS</span></span><br><span class="line">	<span class="comment">//则返回true，如果为INTERFACES，则返回false</span></span><br><span class="line">	<span class="keyword">boolean</span> proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);</span><br><span class="line">	<span class="comment">//为注册的Bean创建相应模式的代理对象</span></span><br><span class="line">	<span class="keyword">return</span> ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="5）BeanDefinitionReaderUtils向容器注册Bean"><a href="#5）BeanDefinitionReaderUtils向容器注册Bean" class="headerlink" title="5）BeanDefinitionReaderUtils向容器注册Bean"></a>5）BeanDefinitionReaderUtils向容器注册Bean</h4><p>BeanDefinitionReaderUtils 主要是校验BeanDefinition信息，然后将Bean添加到容器中一个管理BeanDefinition的HashMap中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//将解析的BeanDefinitionHold注册到容器中</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">registerBeanDefinition</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)</span></span></span><br><span class="line"><span class="function">		<span class="keyword">throws</span> BeanDefinitionStoreException </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// Register bean definition under primary name.</span></span><br><span class="line">	<span class="comment">//获取解析的BeanDefinition的名称</span></span><br><span class="line">	String beanName = definitionHolder.getBeanName();</span><br><span class="line">	<span class="comment">//向IOC容器注册BeanDefinition</span></span><br><span class="line">	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());</span><br><span class="line"></span><br><span class="line">	<span class="comment">// Register aliases for bean name, if any.</span></span><br><span class="line">	<span class="comment">//如果解析的BeanDefinition有别名，向容器为其注册别名</span></span><br><span class="line">	String[] aliases = definitionHolder.getAliases();</span><br><span class="line">	<span class="keyword">if</span> (aliases != <span class="keyword">null</span>) &#123;</span><br><span class="line">		<span class="keyword">for</span> (String alias : aliases) &#123;</span><br><span class="line">			registry.registerAlias(beanName, alias);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="扫描指定包并解析为BeanDefinition"><a href="#扫描指定包并解析为BeanDefinition" class="headerlink" title="扫描指定包并解析为BeanDefinition"></a>扫描指定包并解析为BeanDefinition</h3><p>当创建注解处理容器时，如果传入的初始参数是注解Bean定义类所在的包时，注解容器将扫描给定的包及其子包，将扫描到的注解Bean定义载入并注册。</p>
<h4 id="1）ClassPathBeanDefinitionScanner扫描给定的包及其子包"><a href="#1）ClassPathBeanDefinitionScanner扫描给定的包及其子包" class="headerlink" title="1）ClassPathBeanDefinitionScanner扫描给定的包及其子包"></a>1）ClassPathBeanDefinitionScanner扫描给定的包及其子包</h4><p>AnnotationConfigApplicationContext通过调用类路径Bean定义扫描器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//该构造函数会自动扫描以给定的包及其子包下的所有类，并自动识别所有的Spring Bean，将其注册到容器中</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">AnnotationConfigApplicationContext</span><span class="params">(String... basePackages)</span> </span>&#123;</span><br><span class="line">	<span class="keyword">this</span>();</span><br><span class="line">	scan(basePackages);</span><br><span class="line">	refresh();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//扫描指定包路径及其子包下的注解类，为了使新添加的类被处理，必须手动调用</span></span><br><span class="line"><span class="comment">//refresh()方法刷新容器</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">scan</span><span class="params">(String... basePackages)</span> </span>&#123;</span><br><span class="line">	Assert.notEmpty(basePackages, <span class="string">"At least one base package must be specified"</span>);</span><br><span class="line">   <span class="comment">// 该scanner 为 ClassPathBeanDefinitionScanner</span></span><br><span class="line">	<span class="keyword">this</span>.scanner.scan(basePackages);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>ClassPathBeanDefinitionScanner扫描给定包及其子包下的所有类，主要源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line">	<span class="comment">//创建一个类路径Bean定义扫描器</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ClassPathBeanDefinitionScanner</span><span class="params">(BeanDefinitionRegistry registry)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>(registry, <span class="keyword">true</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//为容器创建一个类路径Bean定义扫描器，并指定是否使用默认的扫描过滤规则。</span></span><br><span class="line">	<span class="comment">//即Spring默认扫描配置：@Component、@Repository、@Service、@Controller</span></span><br><span class="line">	<span class="comment">//注解的Bean，同时也支持JavaEE6的@ManagedBean和JSR-330的@Named注解</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ClassPathBeanDefinitionScanner</span><span class="params">(BeanDefinitionRegistry registry, <span class="keyword">boolean</span> useDefaultFilters)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>(registry, useDefaultFilters, getOrCreateEnvironment(registry));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用类路径Bean定义扫描器入口方法</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">scan</span><span class="params">(String... basePackages)</span> </span>&#123;</span><br><span class="line">		<span class="comment">//获取容器中已经注册的Bean个数</span></span><br><span class="line">		<span class="keyword">int</span> beanCountAtScanStart = <span class="keyword">this</span>.registry.getBeanDefinitionCount();</span><br><span class="line"></span><br><span class="line">		<span class="comment">//启动扫描器扫描给定包</span></span><br><span class="line">		doScan(basePackages);</span><br><span class="line"></span><br><span class="line">		<span class="comment">// Register annotation config processors, if necessary.</span></span><br><span class="line">		<span class="comment">//注册注解配置(Annotation config)处理器</span></span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.includeAnnotationConfig) &#123;</span><br><span class="line">			AnnotationConfigUtils.registerAnnotationConfigProcessors(<span class="keyword">this</span>.registry);</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		<span class="comment">//返回注册的Bean个数</span></span><br><span class="line">		<span class="keyword">return</span> (<span class="keyword">this</span>.registry.getBeanDefinitionCount() - beanCountAtScanStart);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//类路径Bean定义扫描器扫描给定包及其子包</span></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> Set&lt;BeanDefinitionHolder&gt; <span class="title">doScan</span><span class="params">(String... basePackages)</span> </span>&#123;</span><br><span class="line">		Assert.notEmpty(basePackages, <span class="string">"At least one base package must be specified"</span>);</span><br><span class="line">		<span class="comment">//创建一个集合，存放扫描到Bean定义的封装类</span></span><br><span class="line">		Set&lt;BeanDefinitionHolder&gt; beanDefinitions = <span class="keyword">new</span> LinkedHashSet&lt;&gt;();</span><br><span class="line">		<span class="comment">//遍历扫描所有给定的包</span></span><br><span class="line">		<span class="keyword">for</span> (String basePackage : basePackages) &#123;</span><br><span class="line">			<span class="comment">//调用父类ClassPathScanningCandidateComponentProvider的方法</span></span><br><span class="line">			<span class="comment">//扫描给定类路径，获取符合条件的Bean定义</span></span><br><span class="line">			Set&lt;BeanDefinition&gt; candidates = findCandidateComponents(basePackage);</span><br><span class="line">			<span class="comment">//遍历扫描到的Bean</span></span><br><span class="line">			<span class="keyword">for</span> (BeanDefinition candidate : candidates) &#123;</span><br><span class="line">				<span class="comment">//获取Bean定义类中@Scope注解的值，即获取Bean的作用域</span></span><br><span class="line">				ScopeMetadata scopeMetadata = <span class="keyword">this</span>.scopeMetadataResolver.resolveScopeMetadata(candidate);</span><br><span class="line">				<span class="comment">//为Bean设置注解配置的作用域</span></span><br><span class="line">				candidate.setScope(scopeMetadata.getScopeName());</span><br><span class="line">				<span class="comment">//为Bean生成名称</span></span><br><span class="line">				String beanName = <span class="keyword">this</span>.beanNameGenerator.generateBeanName(candidate, <span class="keyword">this</span>.registry);</span><br><span class="line">				<span class="comment">//如果扫描到的Bean不是Spring的注解Bean，则为Bean设置默认值，</span></span><br><span class="line">				<span class="comment">//设置Bean的自动依赖注入装配属性等</span></span><br><span class="line">				<span class="keyword">if</span> (candidate <span class="keyword">instanceof</span> AbstractBeanDefinition) &#123;</span><br><span class="line">					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);</span><br><span class="line">				&#125;</span><br><span class="line">				<span class="comment">//如果扫描到的Bean是Spring的注解Bean，则处理其通用的Spring注解</span></span><br><span class="line">				<span class="keyword">if</span> (candidate <span class="keyword">instanceof</span> AnnotatedBeanDefinition) &#123;</span><br><span class="line">					<span class="comment">//处理注解Bean中通用的注解，在分析注解Bean定义类读取器时已经分析过</span></span><br><span class="line">					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);</span><br><span class="line">				&#125;</span><br><span class="line">				<span class="comment">//根据Bean名称检查指定的Bean是否需要在容器中注册，或者在容器中冲突</span></span><br><span class="line">				<span class="keyword">if</span> (checkCandidate(beanName, candidate)) &#123;</span><br><span class="line">					BeanDefinitionHolder definitionHolder = <span class="keyword">new</span> BeanDefinitionHolder(candidate, beanName);</span><br><span class="line">					<span class="comment">//根据注解中配置的作用域，为Bean应用相应的代理模式</span></span><br><span class="line">					definitionHolder =</span><br><span class="line">							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, <span class="keyword">this</span>.registry);</span><br><span class="line">					beanDefinitions.add(definitionHolder);</span><br><span class="line">					<span class="comment">//向容器注册扫描到的Bean</span></span><br><span class="line">					registerBeanDefinition(definitionHolder, <span class="keyword">this</span>.registry);</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> beanDefinitions;</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>

<p>类路径Bean定义扫描器ClassPathBeanDefinitionScanner主要通过<code>findCandidateComponents()</code>方法调用其父类ClassPathScanningCandidateComponentProvider类来扫描获取给定包及其子包下的类。</p>
<h4 id="2）ClassPathScanningCandidateComponentProvider扫描给定包及其子包的类"><a href="#2）ClassPathScanningCandidateComponentProvider扫描给定包及其子包的类" class="headerlink" title="2）ClassPathScanningCandidateComponentProvider扫描给定包及其子包的类"></a>2）ClassPathScanningCandidateComponentProvider扫描给定包及其子包的类</h4><p>ClassPathScanningCandidateComponentProvider类的f<code>indCandidateComponents()</code>方法具体实现扫描给定类路径包的功能，主要源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassPathScanningCandidateComponentProvider</span> <span class="keyword">implements</span> <span class="title">EnvironmentCapable</span>, <span class="title">ResourceLoaderAware</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_RESOURCE_PATTERN = <span class="string">"**/*.class"</span>;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">final</span> Log logger = LogFactory.getLog(getClass());</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> String resourcePattern = DEFAULT_RESOURCE_PATTERN;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//保存过滤规则要包含的注解，即Spring默认的@Component、@Repository、@Service、</span></span><br><span class="line">	<span class="comment">//@Controller注解的Bean，以及JavaEE6的@ManagedBean和JSR-330的@Named注解</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">final</span> List&lt;TypeFilter&gt; includeFilters = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">	<span class="comment">//保存过滤规则要排除的注解</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">final</span> List&lt;TypeFilter&gt; excludeFilters = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Nullable</span></span><br><span class="line">	<span class="keyword">private</span> Environment environment;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Nullable</span></span><br><span class="line">	<span class="keyword">private</span> ConditionEvaluator conditionEvaluator;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Nullable</span></span><br><span class="line">	<span class="keyword">private</span> ResourcePatternResolver resourcePatternResolver;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Nullable</span></span><br><span class="line">	<span class="keyword">private</span> MetadataReaderFactory metadataReaderFactory;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Nullable</span></span><br><span class="line">	<span class="keyword">private</span> CandidateComponentsIndex componentsIndex;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Protected constructor for flexible subclass initialization.</span></span><br><span class="line"><span class="comment">	 * <span class="doctag">@since</span> 4.3.6</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> <span class="title">ClassPathScanningCandidateComponentProvider</span><span class="params">()</span> </span>&#123;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//构造方法，该方法在子类ClassPathBeanDefinitionScanner的构造方法中被调用</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ClassPathScanningCandidateComponentProvider</span><span class="params">(<span class="keyword">boolean</span> useDefaultFilters)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>(useDefaultFilters, <span class="keyword">new</span> StandardEnvironment());</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ClassPathScanningCandidateComponentProvider</span><span class="params">(<span class="keyword">boolean</span> useDefaultFilters, Environment environment)</span> </span>&#123;</span><br><span class="line">		<span class="comment">//如果使用Spring默认的过滤规则，则向容器注册过滤规则</span></span><br><span class="line">		<span class="keyword">if</span> (useDefaultFilters) &#123;</span><br><span class="line">			registerDefaultFilters();</span><br><span class="line">		&#125;</span><br><span class="line">		setEnvironment(environment);</span><br><span class="line">		setResourceLoader(<span class="keyword">null</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setResourcePattern</span><span class="params">(String resourcePattern)</span> </span>&#123;</span><br><span class="line">		Assert.notNull(resourcePattern, <span class="string">"'resourcePattern' must not be null"</span>);</span><br><span class="line">		<span class="keyword">this</span>.resourcePattern = resourcePattern;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Add an include type filter to the &lt;i&gt;end&lt;/i&gt; of the inclusion list.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addIncludeFilter</span><span class="params">(TypeFilter includeFilter)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.includeFilters.add(includeFilter);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Add an exclude type filter to the &lt;i&gt;front&lt;/i&gt; of the exclusion list.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addExcludeFilter</span><span class="params">(TypeFilter excludeFilter)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.excludeFilters.add(<span class="number">0</span>, excludeFilter);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">resetFilters</span><span class="params">(<span class="keyword">boolean</span> useDefaultFilters)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.includeFilters.clear();</span><br><span class="line">		<span class="keyword">this</span>.excludeFilters.clear();</span><br><span class="line">		<span class="keyword">if</span> (useDefaultFilters) &#123;</span><br><span class="line">			registerDefaultFilters();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//向容器注册过滤规则</span></span><br><span class="line">	<span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line">	<span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">registerDefaultFilters</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="comment">//向要包含的过滤规则中添加@Component注解类，注意Spring中@Repository</span></span><br><span class="line">		<span class="comment">//@Service和@Controller都是Component，因为这些注解都添加了@Component注解</span></span><br><span class="line">		<span class="keyword">this</span>.includeFilters.add(<span class="keyword">new</span> AnnotationTypeFilter(Component<span class="class">.<span class="keyword">class</span>))</span>;</span><br><span class="line">		<span class="comment">//获取当前类的类加载器</span></span><br><span class="line">		ClassLoader cl = ClassPathScanningCandidateComponentProvider<span class="class">.<span class="keyword">class</span>.<span class="title">getClassLoader</span>()</span>;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			<span class="comment">//向要包含的过滤规则添加JavaEE6的@ManagedBean注解</span></span><br><span class="line">			<span class="keyword">this</span>.includeFilters.add(<span class="keyword">new</span> AnnotationTypeFilter(</span><br><span class="line">					((Class&lt;? extends Annotation&gt;) ClassUtils.forName(<span class="string">"javax.annotation.ManagedBean"</span>, cl)), <span class="keyword">false</span>));</span><br><span class="line">			logger.debug(<span class="string">"JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</span><br><span class="line">			<span class="comment">// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.</span></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			<span class="comment">//向要包含的过滤规则添加@Named注解</span></span><br><span class="line">			<span class="keyword">this</span>.includeFilters.add(<span class="keyword">new</span> AnnotationTypeFilter(</span><br><span class="line">					((Class&lt;? extends Annotation&gt;) ClassUtils.forName(<span class="string">"javax.inject.Named"</span>, cl)), <span class="keyword">false</span>));</span><br><span class="line">			logger.debug(<span class="string">"JSR-330 'javax.inject.Named' annotation found and supported for component scanning"</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</span><br><span class="line">			<span class="comment">// JSR-330 API not available - simply skip.</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setEnvironment</span><span class="params">(Environment environment)</span> </span>&#123;</span><br><span class="line">		Assert.notNull(environment, <span class="string">"Environment must not be null"</span>);</span><br><span class="line">		<span class="keyword">this</span>.environment = environment;</span><br><span class="line">		<span class="keyword">this</span>.conditionEvaluator = <span class="keyword">null</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">final</span> Environment <span class="title">getEnvironment</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.environment == <span class="keyword">null</span>) &#123;</span><br><span class="line">			<span class="keyword">this</span>.environment = <span class="keyword">new</span> StandardEnvironment();</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.environment;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Return the &#123;<span class="doctag">@link</span> BeanDefinitionRegistry&#125; used by this scanner, if any.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="meta">@Nullable</span></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> BeanDefinitionRegistry <span class="title">getRegistry</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setResourceLoader</span><span class="params">(@Nullable ResourceLoader resourceLoader)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);</span><br><span class="line">		<span class="keyword">this</span>.metadataReaderFactory = <span class="keyword">new</span> CachingMetadataReaderFactory(resourceLoader);</span><br><span class="line">		<span class="keyword">this</span>.componentsIndex = CandidateComponentsIndexLoader.loadIndex(<span class="keyword">this</span>.resourcePatternResolver.getClassLoader());</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Return the ResourceLoader that this component provider uses.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">final</span> ResourceLoader <span class="title">getResourceLoader</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> getResourcePatternResolver();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> ResourcePatternResolver <span class="title">getResourcePatternResolver</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.resourcePatternResolver == <span class="keyword">null</span>) &#123;</span><br><span class="line">			<span class="keyword">this</span>.resourcePatternResolver = <span class="keyword">new</span> PathMatchingResourcePatternResolver();</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.resourcePatternResolver;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMetadataReaderFactory</span><span class="params">(MetadataReaderFactory metadataReaderFactory)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.metadataReaderFactory = metadataReaderFactory;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Return the MetadataReaderFactory used by this component provider.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">final</span> MetadataReaderFactory <span class="title">getMetadataReaderFactory</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.metadataReaderFactory == <span class="keyword">null</span>) &#123;</span><br><span class="line">			<span class="keyword">this</span>.metadataReaderFactory = <span class="keyword">new</span> CachingMetadataReaderFactory();</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.metadataReaderFactory;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//扫描给定类路径的包</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Set&lt;BeanDefinition&gt; <span class="title">findCandidateComponents</span><span class="params">(String basePackage)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.componentsIndex != <span class="keyword">null</span> &amp;&amp; indexSupportsIncludeFilters()) &#123;</span><br><span class="line">			<span class="keyword">return</span> addCandidateComponentsFromIndex(<span class="keyword">this</span>.componentsIndex, basePackage);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="keyword">return</span> scanCandidateComponents(basePackage);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">indexSupportsIncludeFilters</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">for</span> (TypeFilter includeFilter : <span class="keyword">this</span>.includeFilters) &#123;</span><br><span class="line">			<span class="keyword">if</span> (!indexSupportsIncludeFilter(includeFilter)) &#123;</span><br><span class="line">				<span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">indexSupportsIncludeFilter</span><span class="params">(TypeFilter filter)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (filter <span class="keyword">instanceof</span> AnnotationTypeFilter) &#123;</span><br><span class="line">			Class&lt;? extends Annotation&gt; annotation = ((AnnotationTypeFilter) filter).getAnnotationType();</span><br><span class="line">			<span class="keyword">return</span> (AnnotationUtils.isAnnotationDeclaredLocally(Indexed<span class="class">.<span class="keyword">class</span>, <span class="title">annotation</span>) ||</span></span><br><span class="line">					annotation.getName().startsWith("javax."));</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (filter <span class="keyword">instanceof</span> AssignableTypeFilter) &#123;</span><br><span class="line">			Class&lt;?&gt; target = ((AssignableTypeFilter) filter).getTargetType();</span><br><span class="line">			<span class="keyword">return</span> AnnotationUtils.isAnnotationDeclaredLocally(Indexed<span class="class">.<span class="keyword">class</span>, <span class="title">target</span>)</span>;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Nullable</span></span><br><span class="line">	<span class="function"><span class="keyword">private</span> String <span class="title">extractStereotype</span><span class="params">(TypeFilter filter)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (filter <span class="keyword">instanceof</span> AnnotationTypeFilter) &#123;</span><br><span class="line">			<span class="keyword">return</span> ((AnnotationTypeFilter) filter).getAnnotationType().getName();</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (filter <span class="keyword">instanceof</span> AssignableTypeFilter) &#123;</span><br><span class="line">			<span class="keyword">return</span> ((AssignableTypeFilter) filter).getTargetType().getName();</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> Set&lt;BeanDefinition&gt; <span class="title">addCandidateComponentsFromIndex</span><span class="params">(CandidateComponentsIndex index, String basePackage)</span> </span>&#123;</span><br><span class="line">		<span class="comment">//创建存储扫描到的类的集合</span></span><br><span class="line">		Set&lt;BeanDefinition&gt; candidates = <span class="keyword">new</span> LinkedHashSet&lt;&gt;();</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			Set&lt;String&gt; types = <span class="keyword">new</span> HashSet&lt;&gt;();</span><br><span class="line">			<span class="keyword">for</span> (TypeFilter filter : <span class="keyword">this</span>.includeFilters) &#123;</span><br><span class="line">				String stereotype = extractStereotype(filter);</span><br><span class="line">				<span class="keyword">if</span> (stereotype == <span class="keyword">null</span>) &#123;</span><br><span class="line">					<span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Failed to extract stereotype from "</span>+ filter);</span><br><span class="line">				&#125;</span><br><span class="line">				types.addAll(index.getCandidateTypes(basePackage, stereotype));</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="keyword">boolean</span> traceEnabled = logger.isTraceEnabled();</span><br><span class="line">			<span class="keyword">boolean</span> debugEnabled = logger.isDebugEnabled();</span><br><span class="line">			<span class="keyword">for</span> (String type : types) &#123;</span><br><span class="line">				<span class="comment">//为指定资源获取元数据读取器，元信息读取器通过汇编(ASM)读//取资源元信息</span></span><br><span class="line">				MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);</span><br><span class="line">				<span class="comment">//如果扫描到的类符合容器配置的过滤规则</span></span><br><span class="line">				<span class="keyword">if</span> (isCandidateComponent(metadataReader)) &#123;</span><br><span class="line">					<span class="comment">//通过汇编(ASM)读取资源字节码中的Bean定义元信息</span></span><br><span class="line">					AnnotatedGenericBeanDefinition sbd = <span class="keyword">new</span> AnnotatedGenericBeanDefinition(</span><br><span class="line">							metadataReader.getAnnotationMetadata());</span><br><span class="line">					<span class="keyword">if</span> (isCandidateComponent(sbd)) &#123;</span><br><span class="line">						<span class="keyword">if</span> (debugEnabled) &#123;</span><br><span class="line">							logger.debug(<span class="string">"Using candidate component class from index: "</span> + type);</span><br><span class="line">						&#125;</span><br><span class="line">						candidates.add(sbd);</span><br><span class="line">					&#125;</span><br><span class="line">					<span class="keyword">else</span> &#123;</span><br><span class="line">						<span class="keyword">if</span> (debugEnabled) &#123;</span><br><span class="line">							logger.debug(<span class="string">"Ignored because not a concrete top-level class: "</span> + type);</span><br><span class="line">						&#125;</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;</span><br><span class="line">				<span class="keyword">else</span> &#123;</span><br><span class="line">					<span class="keyword">if</span> (traceEnabled) &#123;</span><br><span class="line">						logger.trace(<span class="string">"Ignored because matching an exclude filter: "</span> + type);</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (IOException ex) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> BeanDefinitionStoreException(<span class="string">"I/O failure during classpath scanning"</span>, ex);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> candidates;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> Set&lt;BeanDefinition&gt; <span class="title">scanCandidateComponents</span><span class="params">(String basePackage)</span> </span>&#123;</span><br><span class="line">		Set&lt;BeanDefinition&gt; candidates = <span class="keyword">new</span> LinkedHashSet&lt;&gt;();</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +</span><br><span class="line">					resolveBasePackage(basePackage) + <span class="string">'/'</span> + <span class="keyword">this</span>.resourcePattern;</span><br><span class="line">			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);</span><br><span class="line">			<span class="keyword">boolean</span> traceEnabled = logger.isTraceEnabled();</span><br><span class="line">			<span class="keyword">boolean</span> debugEnabled = logger.isDebugEnabled();</span><br><span class="line">			<span class="keyword">for</span> (Resource resource : resources) &#123;</span><br><span class="line">				<span class="keyword">if</span> (traceEnabled) &#123;</span><br><span class="line">					logger.trace(<span class="string">"Scanning "</span> + resource);</span><br><span class="line">				&#125;</span><br><span class="line">				<span class="keyword">if</span> (resource.isReadable()) &#123;</span><br><span class="line">					<span class="keyword">try</span> &#123;</span><br><span class="line">						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);</span><br><span class="line">						<span class="keyword">if</span> (isCandidateComponent(metadataReader)) &#123;</span><br><span class="line">							ScannedGenericBeanDefinition sbd = <span class="keyword">new</span> ScannedGenericBeanDefinition(metadataReader);</span><br><span class="line">							sbd.setResource(resource);</span><br><span class="line">							sbd.setSource(resource);</span><br><span class="line">							<span class="keyword">if</span> (isCandidateComponent(sbd)) &#123;</span><br><span class="line">								<span class="keyword">if</span> (debugEnabled) &#123;</span><br><span class="line">									logger.debug(<span class="string">"Identified candidate component class: "</span> + resource);</span><br><span class="line">								&#125;</span><br><span class="line">								candidates.add(sbd);</span><br><span class="line">							&#125;</span><br><span class="line">							<span class="keyword">else</span> &#123;</span><br><span class="line">								<span class="keyword">if</span> (debugEnabled) &#123;</span><br><span class="line">									logger.debug(<span class="string">"Ignored because not a concrete top-level class: "</span> + resource);</span><br><span class="line">								&#125;</span><br><span class="line">							&#125;</span><br><span class="line">						&#125;</span><br><span class="line">						<span class="keyword">else</span> &#123;</span><br><span class="line">							<span class="keyword">if</span> (traceEnabled) &#123;</span><br><span class="line">								logger.trace(<span class="string">"Ignored because not matching any filter: "</span> + resource);</span><br><span class="line">							&#125;</span><br><span class="line">						&#125;</span><br><span class="line">					&#125;</span><br><span class="line">					<span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">						<span class="keyword">throw</span> <span class="keyword">new</span> BeanDefinitionStoreException(</span><br><span class="line">								<span class="string">"Failed to read candidate component class: "</span> + resource, ex);</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;</span><br><span class="line">				<span class="keyword">else</span> &#123;</span><br><span class="line">					<span class="keyword">if</span> (traceEnabled) &#123;</span><br><span class="line">						logger.trace(<span class="string">"Ignored because not readable: "</span> + resource);</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (IOException ex) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> BeanDefinitionStoreException(<span class="string">"I/O failure during classpath scanning"</span>, ex);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> candidates;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> String <span class="title">resolveBasePackage</span><span class="params">(String basePackage)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//判断元信息读取器读取的类是否符合容器定义的注解过滤规则</span></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isCandidateComponent</span><span class="params">(MetadataReader metadataReader)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">		<span class="comment">//如果读取的类的注解在排除注解过滤规则中，返回false</span></span><br><span class="line">		<span class="keyword">for</span> (TypeFilter tf : <span class="keyword">this</span>.excludeFilters) &#123;</span><br><span class="line">			<span class="keyword">if</span> (tf.match(metadataReader, getMetadataReaderFactory())) &#123;</span><br><span class="line">				<span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">//如果读取的类的注解在包含的注解的过滤规则中，则返回ture</span></span><br><span class="line">		<span class="keyword">for</span> (TypeFilter tf : <span class="keyword">this</span>.includeFilters) &#123;</span><br><span class="line">			<span class="keyword">if</span> (tf.match(metadataReader, getMetadataReaderFactory())) &#123;</span><br><span class="line">				<span class="keyword">return</span> isConditionMatch(metadataReader);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">//如果读取的类的注解既不在排除规则，也不在包含规则中，则返回false</span></span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isConditionMatch</span><span class="params">(MetadataReader metadataReader)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.conditionEvaluator == <span class="keyword">null</span>) &#123;</span><br><span class="line">			<span class="keyword">this</span>.conditionEvaluator =</span><br><span class="line">					<span class="keyword">new</span> ConditionEvaluator(getRegistry(), <span class="keyword">this</span>.environment, <span class="keyword">this</span>.resourcePatternResolver);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> !<span class="keyword">this</span>.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isCandidateComponent</span><span class="params">(AnnotatedBeanDefinition beanDefinition)</span> </span>&#123;</span><br><span class="line">		AnnotationMetadata metadata = beanDefinition.getMetadata();</span><br><span class="line">		<span class="keyword">return</span> (metadata.isIndependent() &amp;&amp; (metadata.isConcrete() ||</span><br><span class="line">				(metadata.isAbstract() &amp;&amp; metadata.hasAnnotatedMethods(Lookup<span class="class">.<span class="keyword">class</span>.<span class="title">getName</span>()))))</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Clear the local metadata cache, if any, removing all cached class metadata.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clearCache</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.metadataReaderFactory <span class="keyword">instanceof</span> CachingMetadataReaderFactory) &#123;</span><br><span class="line">			<span class="comment">// Clear cache in externally provided MetadataReaderFactory; this is a no-op</span></span><br><span class="line">			<span class="comment">// for a shared cache since it'll be cleared by the ApplicationContext.</span></span><br><span class="line">			((CachingMetadataReaderFactory) <span class="keyword">this</span>.metadataReaderFactory).clearCache();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="注册注解BeanDefinition"><a href="#注册注解BeanDefinition" class="headerlink" title="注册注解BeanDefinition"></a>注册注解BeanDefinition</h3><p>AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的Web版，它们对于注解Bean的注册和扫描是基本相同的，但是AnnotationConfigWebApplicationContext对注解Bean定义的载入稍有不同，AnnotationConfiqWebApplicationContext注入注解Bean定义源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//载入注解Bean定义资源</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">loadBeanDefinitions</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> </span>&#123;</span><br><span class="line">	<span class="comment">//为容器设置注解Bean定义读取器</span></span><br><span class="line">	AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);</span><br><span class="line">	<span class="comment">//为容器设置类路径Bean定义扫描器</span></span><br><span class="line">	ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);</span><br><span class="line"></span><br><span class="line">	<span class="comment">//获取容器的Bean名称生成器</span></span><br><span class="line">	BeanNameGenerator beanNameGenerator = getBeanNameGenerator();</span><br><span class="line">	<span class="comment">//为注解Bean定义读取器和类路径扫描器设置Bean名称生成器</span></span><br><span class="line">	<span class="keyword">if</span> (beanNameGenerator != <span class="keyword">null</span>) &#123;</span><br><span class="line">		reader.setBeanNameGenerator(beanNameGenerator);</span><br><span class="line">		scanner.setBeanNameGenerator(beanNameGenerator);</span><br><span class="line">		beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//获取容器的作用域元信息解析器</span></span><br><span class="line">	ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();</span><br><span class="line">	<span class="comment">//为注解Bean定义读取器和类路径扫描器设置作用域元信息解析器</span></span><br><span class="line">	<span class="keyword">if</span> (scopeMetadataResolver != <span class="keyword">null</span>) &#123;</span><br><span class="line">		reader.setScopeMetadataResolver(scopeMetadataResolver);</span><br><span class="line">		scanner.setScopeMetadataResolver(scopeMetadataResolver);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!<span class="keyword">this</span>.annotatedClasses.isEmpty()) &#123;</span><br><span class="line">		<span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">			logger.info(<span class="string">"Registering annotated classes: ["</span> +</span><br><span class="line">					StringUtils.collectionToCommaDelimitedString(<span class="keyword">this</span>.annotatedClasses) + <span class="string">"]"</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		reader.register(<span class="keyword">this</span>.annotatedClasses.toArray(<span class="keyword">new</span> Class&lt;?&gt;[<span class="keyword">this</span>.annotatedClasses.size()]));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!<span class="keyword">this</span>.basePackages.isEmpty()) &#123;</span><br><span class="line">		<span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">			logger.info(<span class="string">"Scanning base packages: ["</span> +</span><br><span class="line">					StringUtils.collectionToCommaDelimitedString(<span class="keyword">this</span>.basePackages) + <span class="string">"]"</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		scanner.scan(<span class="keyword">this</span>.basePackages.toArray(<span class="keyword">new</span> String[<span class="keyword">this</span>.basePackages.size()]));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//获取容器定义的Bean定义资源路径</span></span><br><span class="line">	String[] configLocations = getConfigLocations();</span><br><span class="line">	<span class="comment">//如果定位的Bean定义资源路径不为空</span></span><br><span class="line">	<span class="keyword">if</span> (configLocations != <span class="keyword">null</span>) &#123;</span><br><span class="line">		<span class="keyword">for</span> (String configLocation : configLocations) &#123;</span><br><span class="line">			<span class="keyword">try</span> &#123;</span><br><span class="line">				<span class="comment">//使用当前容器的类加载器加载定位路径的字节码类文件</span></span><br><span class="line">				Class&lt;?&gt; clazz = ClassUtils.forName(configLocation, getClassLoader());</span><br><span class="line">				<span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">					logger.info(<span class="string">"Successfully resolved class for ["</span> + configLocation + <span class="string">"]"</span>);</span><br><span class="line">				&#125;</span><br><span class="line">				reader.register(clazz);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</span><br><span class="line">				<span class="keyword">if</span> (logger.isDebugEnabled()) &#123;</span><br><span class="line">					logger.debug(<span class="string">"Could not load class for config location ["</span> + configLocation +</span><br><span class="line">							<span class="string">"] - trying package scan. "</span> + ex);</span><br><span class="line">				&#125;</span><br><span class="line">				<span class="comment">//如果容器类加载器加载定义路径的Bean定义资源失败</span></span><br><span class="line">				<span class="comment">//则启用容器类路径扫描器扫描给定路径包及其子包中的类</span></span><br><span class="line">				<span class="keyword">int</span> count = scanner.scan(configLocation);</span><br><span class="line">				<span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">					<span class="keyword">if</span> (count == <span class="number">0</span>) &#123;</span><br><span class="line">						logger.info(<span class="string">"No annotated classes found for specified class/package ["</span> + configLocation + <span class="string">"]"</span>);</span><br><span class="line">					&#125;</span><br><span class="line">					<span class="keyword">else</span> &#123;</span><br><span class="line">						logger.info(<span class="string">"Found "</span> + count + <span class="string">" annotated classes in package ["</span> + configLocation + <span class="string">"]"</span>);</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="IOC容器初始化小结"><a href="#IOC容器初始化小结" class="headerlink" title="IOC容器初始化小结"></a>IOC容器初始化小结</h1><p>总结一下I0C容器初始化的基本步骤：</p>
<p>1、初始化的入口在容器实现中的<code>refresh()</code>调用来完成。</p>
<p>2、对Bean定义载入IOC容器使用的方法是<code>loadBeanDefinition()</code>，其中的大致过程如下：</p>
<p>通过ResourceLoader来完成资源文件位置的定位，DefaultResourceloader是默认的实现，同时上下文本身就给出了Resourceloader的实现，可以从类路径，文件系统，URL等方式来定位资源位置。如果是XmlBeanFactory作为IOC容器，那么需要为它指定Bean定义的资源，也就是说Bean定义文件时通过抽象成Resource来被IOC容器处理的，容器通过BeanDefinitionReader 来完成定义信息的解析和Bean信息的注册，往往使用的是XmlBeanDefinitionReader来解析Bean的XML定义文件。</p>
<p>实际的处理过程是委托给BeanDefinitionParserDelegate来完成的，从而得到bean的定义信息，这些信息在Spring中使用BeanDefinition对象来表示，这个名字可以想到loadBeanDefinition()，registerBeanDefinition()这些相关方法。</p>
<p>它们都是为处理BeanDefinitin服务的，容器解析得到BeanDefinition以后，需要把它在IOC容器中注册，这由IOC实现BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护的一个HashMap来保存得到的BeanDefinition的过程。这个HashMap是I0C容器持有Bean信息的场所，以后对Bean的操作都是围绕这个HashMap来实现的。</p>
<p>然后我们就可以通过BeanFactory和ApplicationContext来使用SpringIOC的服务了，在使用IOC容器的时候，我们注意到除了少量粘合代码，绝大多数以正确IOC风格编写的应用程序代码完全不用关心如何到达工厂，因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方，最好是放在对预期使用的上下文有意义的地方，以及代码将实际需要访问工厂的地方。</p>
<p>Spring本身提供了对声明式载入web应用程序用法的应用程序上下文，并将其存储在ServletContext中的框架实现。</p>
<p>容器初始化全过程的时序图：</p>
<p><img src="https://tu.dxysun.com/%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E6%89%8B%E7%BB%98Spring%20IoC%E8%BF%90%E8%A1%8C%E6%97%B6%E5%BA%8F%E5%9B%BE-20210830232034.jpg" alt=""></p>
 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          打赏
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://dxysun.com/2021/08/30/springForIOCAnnotation/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/spring/" rel="tag">spring</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/2021/09/02/springForBean1/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            spring核心之依赖注入
          
        </div>
      </a>
    
    
      <a href="/2021/08/29/springForMainClass/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">Spring核心之基于xml的IOC容器初始化</div>
      </a>
    
  </nav>

  
   
  
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2015-2024
        <i class="ri-heart-fill heart_icon"></i> dxysun
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        由 <a href="https://hexo.io" target="_blank">Hexo</a> 强力驱动
        <span class="division">|</span>
        主题 - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
        <li>
          <a href="https://beian.miit.gov.cn" target="_black" rel="nofollow">豫ICP备17012675号-1</a>
        </li>
        
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="https://dxysun.com/static/logo.png" alt="迎着朝阳"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/photos">相册</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">友链</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="https://tu.dxysun.com/alipay-20201219151322.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="https://tu.dxysun.com/weixin-20201219151346.png">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->


<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: 'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto'
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>

<!-- MathJax -->

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
      tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
      }
  });

  MathJax.Hub.Queue(function() {
      var all = MathJax.Hub.getAllJax(), i;
      for(i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
      }
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/mathjax@2.7.6/unpacked/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script>
  var ayerConfig = {
    mathjax: true
  }
</script>

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


<script src="/js/dz.js"></script>



    
  </div>
</body>

</html>